/**
 * @description axios 模块
 * @author LI
 * @date 2020-11-18 11:00
 */
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import { CreateAxiosOptions, Result } from '@/utils/axios/types'
import { cloneDeep } from 'lodash-es'

export class VAxios {
  private axiosInstance: AxiosInstance
  private options: CreateAxiosOptions

  constructor(options: CreateAxiosOptions) {
    this.options = options
    this.axiosInstance = axios.create(options)
    this.setupInterceptors()
  }

  private createAxios(config: CreateAxiosOptions): void {
    this.axiosInstance = axios.create(config)
  }

  private getTransform() {
    const { transform } = this.options
    return transform
  }

  getAxios(): AxiosInstance {
    return this.axiosInstance
  }

  /**
   * @description: 重新配置axios
   */
  configAxios(config: CreateAxiosOptions) {
    if (!this.axiosInstance) {
      return
    }
    this.createAxios(config)
  }

  /**
   * @description: 设置通用header
   */
  setHeader(headers: any): void {
    if (!this.axiosInstance) {
      return
    }
    Object.assign(this.axiosInstance.defaults.headers, headers)
  }

  /**
   * @description: 拦截器配置
   */
  private setupInterceptors() {
    const transform = this.getTransform()
    if (!transform) {
      return
    }
    const {
      requestInterceptors,
      requestInterceptorsCatch,
      responseInterceptors,
      responseInterceptorsCatch,
    } = transform

    // 请求拦截器配置处理
    this.axiosInstance.interceptors.request.use((config: AxiosRequestConfig) => {
      if (requestInterceptors && typeof requestInterceptors === 'function') {
        config = requestInterceptors(config)
      }
      return config
    }, undefined)

    // 请求拦截器错误捕获
    requestInterceptorsCatch &&
    typeof requestInterceptorsCatch === 'function' &&
    this.axiosInstance.interceptors.request.use(undefined, requestInterceptorsCatch)

    // 响应结果拦截器处理
    this.axiosInstance.interceptors.response.use((response: AxiosResponse<any>) => {
      if (typeof responseInterceptors === 'function') {
        response = responseInterceptors(response)
      }
      return response
    }, undefined)

    // 响应结果拦截器错误捕获
    responseInterceptorsCatch &&
    typeof responseInterceptorsCatch === 'function' &&
    this.axiosInstance.interceptors.response.use(undefined, responseInterceptorsCatch)
  }

  /**
   * @description:   请求方法
   */
  request<T = any>(config: AxiosRequestConfig): Promise<T> {
    let conf: AxiosRequestConfig = cloneDeep(config)
    const transform = this.getTransform()
    const { beforeRequestHook, requestCatch, transformRequestData } = transform || {}
    if (beforeRequestHook && typeof beforeRequestHook === 'function') {
      conf = beforeRequestHook(conf)
    }

    return new Promise((resolve, reject) => {
      this.axiosInstance.request<any, AxiosResponse<Result>>(conf).then((response: AxiosResponse<Result>) => {
        if (transformRequestData && typeof transformRequestData === 'function') {
          resolve(transformRequestData(response))
          return
        }
        resolve((response as unknown) as Promise<T>)
      }).catch((e: Error) => {
        if (requestCatch && typeof requestCatch === 'function') {
          reject(requestCatch(e))
          return
        }
        reject(e)
      })
    })
  }
}
